<?php
/**
 * [LupMisNotAllowedSync]
 * 本代码为系统自动生成代码，请根据自己业务进行修改;
 * 生成时间 2022-02-18 18:16:27;
 * 版权所有 2020-2022 lizhongwen，并保留所有权利;
 * 说明: 这不是一个自由软件！您只能在不用于商业目的的前提下对程序代码进行修改和使用；不允许对程序代码以任何形式任何目的的再发布;
 * 作者: 中文Lee;
 * 作者主页: http://www.lizhongwen.com;
 * 邮箱: 360811363@qq.com;
 * QQ: 360811363;
 */

namespace modules\sys\service\impl;

use application\core\Lib;
use application\core\RedisUtil;
use application\core\Request;
use application\core\SnowFlake;
use Exception;
use modules\sys\component\GetCacheComponent;
use modules\sys\mapper\AccountLoginLogMapper;
use modules\sys\mapper\AccountMapper;
use modules\sys\mapper\AccountTokenMapper;
use modules\sys\mapper\OrgMapper;
use modules\sys\mapper\RoleMapper;
use modules\sys\service\AccountService;

class AccountServiceImpl implements AccountService
{

    private $snowFlake;

    function __construct()
    {
        $this->snowFlake = SnowFlake::instance();
    }

    /**
     * @param array $data
     * @param array $pagePars
     * @return array
     */
    function lists($data = [], $pagePars = []): array
    {
        //查询所有角色
        $orgMapper = new OrgMapper();
        $roleMapper = new RoleMapper();
        $orgRs = $orgMapper->lists();
        //查询所有角色
        $roleRs = $roleMapper->lists();
        $roleRs = array_column($roleRs, NULL, 'id');
        $orgRs = array_column($orgRs, NULL, 'id');
        $lists = AccountMapper::lists($data, $pagePars);
        $rows = $lists['rows'] ?? $lists;
        foreach ($rows as $k => $v) {
            $roleIds = $v['role_ids'];
            $accountRoles = [];
            if (!empty($roleIds)) {
                $roleIdsArr = explode(',', $roleIds);
                foreach ($roleIdsArr as $_roleId) {
                    if ($roleRs[$_roleId]) {
                        $accountRoles[] = $roleRs[$_roleId];
                    }
                }
            }
            if ($lists['rows']) {
                $lists['rows'][$k]['org_row'] = $orgRs[$v['org_id']];
                $lists['rows'][$k]['account_roles'] = $accountRoles;
            } else {
                $lists[$k]['org_row'] = $orgRs[$v['org_id']];
                $lists[$k]['account_roles'] = $accountRoles;
            }
        }
        return $lists;
    }

    /**
     * @param array $data
     * @return array
     */
    function query(array $data): array
    {
        //查询所属机构
        $row = AccountMapper::query($data);
        $orgMapper = new OrgMapper();
        $orgRs = $orgMapper->lists();
        $orgRs = array_column($orgRs, NULL, "id");
        $row['org_row'] = $orgRs[$row['org_id']] ?? [];
        return $row;
    }

    /**
     * @param array $data
     * @return int
     * @throws \Exception
     */
    function add(array $data): int
    {
        //查询是否重复
        $queryByAccountNameRs = AccountMapper::queryByAccountName(['account_name' => $data['account_name']]);
        if (!empty($queryByAccountNameRs)) {
            throw new Exception("该账号已存在，请更换");
        }
        $data['id'] = SnowFlake::instance()->nextId();
        $data['create_time'] = time();
        $data['password'] = Lib::password($data['password']);
        return AccountMapper::add($data);
    }

    /**
     * @param array $data
     * @return int
     * @throws \Exception
     */
    function del(array $data): int
    {

        $ids = $data['ids'];
        if (empty($ids)) {
            throw new Exception("请至少选择一条数据");
        }
        $delNum = 0;
        $idsArr = explode(",", $ids);
        foreach ($idsArr as $id) {
            if ($id <= 5) {
                throw new Exception("包含系统账号不允许删除");
            }
        }
        foreach ($idsArr as $id) {
            $del = AccountMapper::del(['id' => $id]);
            $delNum += $del;
        }
        return $delNum;
    }

    /**
     * @param array $data
     * @return int
     */
    function edit(array $data): int
    {
        if (!empty($data['password'])) $data['password'] = Lib::password($data['password']);
        return AccountMapper::edit($data);
    }

    /**
     * @param array $data
     * @return int
     * @throws \Exception
     */
    function updPwd(array $data): int
    {
        //查询信息
        $password = $data['password'];
        $accountName = $data['account_name'];
        $oldPwd = $data['old_pwd'];

        $uid = Request::getHeader('accessuid');
        if (empty($data['password'])) {
            throw new Exception("密码不能为空！");
        }

        $queryByAccountName = AccountMapper::queryByAccountName(['account_name' => $accountName]);
        if ($queryByAccountName['id'] != $uid) {
            throw new Exception("非法操作！");
        }
        if (Lib::password($oldPwd) != $queryByAccountName['password']) {
            throw new Exception("原密码错误！");
        }

        $edit = AccountMapper::updPwd(['password' => Lib::password($password), 'id' => $uid]);
        if ($edit == 0) {
            throw new Exception("新密码不能和原密码一样！");
        }
        return $edit;
    }

    /**
     * @param $data
     * @return array
     * @throws \Exception
     */
    public function login($data): array
    {
        //判断验证码是否正确
        if (REDIS_ENABLE) {
            $verifyCode = $data['verify_code'];
            $verifyCodeToken = $data['verify_code_token'];
            if (empty($verifyCode)) {
                throw new Exception("验证码不能为空");
            }
            if (empty($verifyCodeToken)) {
                throw new Exception("请刷新页面再试!");
            }
            $redisVerifyCode = RedisUtil::instance()->get($verifyCodeToken);
            if (empty($redisVerifyCode)) {
                throw new Exception("验证码错误或已过期！");
            }
            if (strtolower($redisVerifyCode) != strtolower($verifyCode)) {
                throw new Exception("验证码错误！");
            }

        }
        // 判断登录次数锁定
        $configRes = GetCacheComponent::config();
        $safeIps = $configRes['safe_ips'];
        $safeIps = str_replace("|", ",", $safeIps);
        $loginErrorLock = $configRes['login_error_lock'];
        $loginErrorNum = $configRes['login_error_num'];
        $lockTime = $configRes['lock_time'];
        if ($safeIps != '0.0.0.0') {
            $safeIpsArr = explode(",", $safeIps);
            if (!in_array(Lib::realIp(), $safeIpsArr)) {
                throw new Exception("非法登录");
            }
        }

        $lastLoginTime = 0;
        if ($loginErrorLock == 1) {
            $res = AccountLoginLogMapper::listsByIp([
                'ip' => Lib::realIp()
            ]);
            $errNum = 0;
            foreach ($res as $k => $v) {
                if (0 == $k) {
                    $lastLoginTime = $v['login_time'];
                    if ($v['status'] == 1) {
                        break;
                    }
                }
                if (-1 == $v['status']) {
                    $errNum += 1;
                }
            }
            if ($errNum >= $loginErrorNum) {
                $diffTime = time() - $lastLoginTime;
                if (($lockTime * 60) >= $diffTime) {
                    throw new Exception("连续" . $loginErrorNum . "次登陆失败，请" . $lockTime . "分钟后重试!");
                }
            }
        }
        $res = AccountMapper::queryByAccountName($data);
        //判断该账号的安全ip，多个用逗号隔开
        $accountSafeIps = $res['safe_ips'];
        $accountSafeIps = str_replace("|", ",", $accountSafeIps);
        if ($accountSafeIps != '0.0.0.0') {
            $accountSafeIpsArr = explode(",", $accountSafeIps);
            if (!in_array(Lib::realIp(), $accountSafeIpsArr)) {
                throw new Exception("非法登录");
            }
        }
        $dataLog = [
            'id' => $this->snowFlake->nextId(),
            'account_name' => $data['account_name'],
            'password' => substr($data['password'], 0, 1) . "****" . substr($data['password'], -1),
            'ip' => Lib::realIp(),
            'browser' => Lib::getBrowser(),
            'status' => -1,
            'remarks' => '',
            'login_time' => time(),
            'user_agent' => $_SERVER['HTTP_USER_AGENT']
        ];

        if (empty($res)) {
            $dataLog['status'] = -1;
            $dataLog['remarks'] = '账号或密码错误.';
            AccountLoginLogMapper::add($dataLog);
            throw new Exception("账号或密码错误");
        }
        if (Lib::password($data['password']) != $res['password']) {
            $dataLog['status'] = -1;
            $dataLog['remarks'] = '账号或密码错误！';
            AccountLoginLogMapper::add($dataLog);
            throw new Exception("账号或密码错误!");
        }
        $uid = (string)$res['id'];
        $accountName = $res['account_name'];
        $token = md5(Lib::createOrderNo() . $uid);
        // 判断是否启用redis，如果启用redis则插入redis
        if (REDIS_ENABLE) {
            $Redis = RedisUtil::instance();
            $valArr = [
                'account_id' => $uid,
                'account_name' => $accountName,
                'token' => $token,
                'expire_time' => time() + TOKEN_EXPIRE_TIME,
                'login_time' => time(),
                'ip' => Lib::realIp(),
                'user_agent' => $_SERVER['HTTP_USER_AGENT']
            ];
            $Redis->hSet("sys_account_token", $uid, json_encode($valArr, JSON_UNESCAPED_UNICODE));
        } else {
            // 将token保存在数据库中
            AccountTokenMapper::delByAccountId([
                'account_id' => $uid
            ]);
            AccountTokenMapper::add([
                'id' => $this->snowFlake->nextId(),
                'account_id' => $uid,
                'account_name' => $accountName,
                'token' => $token,
                'expire_time' => time() + TOKEN_EXPIRE_TIME,
                'login_time' => time(),
                'ip' => Lib::realIp(),
                'user_agent' => $_SERVER['HTTP_USER_AGENT']
            ]);
        }
        $dataLog['status'] = 1;
        $dataLog['remarks'] = '登录成功';
        AccountLoginLogMapper::add($dataLog);
        // 登录成功
        if (REDIS_ENABLE) {
            //验证通过删除验证码
            RedisUtil::instance()->del($data['verify_code_token']);
        }
        return [
            "uid" => $uid,
            "token" => $token
        ];
    }
}

